using Sage.Http.Core;
using Sage.Http.Models;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;

namespace Sage.Http.Extensions
{
    /// <summary>
    /// 为HttpRequestManager提供基于RequestOptions的扩展方法
    /// </summary>
    public static class HttpRequestManagerOptionsExtensions
    {
        /// <summary>
        /// 使用请求选项发送请求并反序列化响应
        /// </summary>
        /// <typeparam name="TResult">响应类型</typeparam>
        /// <param name="manager">HTTP请求管理器</param>
        /// <param name="method">HTTP方法</param>
        /// <param name="requestUri">请求URI</param>
        /// <param name="options">请求选项</param>
        /// <returns>反序列化后的响应对象</returns>
        [RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        [RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        public static async Task<TResult?> SendWithOptionsAsync<TResult>(
            this HttpRequestManager manager,
            HttpMethod method,
            string requestUri,
            RequestOptions options)
        {
            ArgumentNullException.ThrowIfNull(manager);
            ArgumentNullException.ThrowIfNull(method);
            ArgumentException.ThrowIfNullOrEmpty(requestUri);
            ArgumentNullException.ThrowIfNull(options);

            var builder = manager.CreateRequestWithOptions(method, requestUri, options);

            using var response = await builder.SendAsync(options.CancellationToken).ConfigureAwait(false);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync(options.CancellationToken).ConfigureAwait(false);
            return await JsonSerializer.DeserializeAsync<TResult>(stream, cancellationToken: options.CancellationToken).ConfigureAwait(false);
        }

        /// <summary>
        /// 使用请求选项发送请求并反序列化响应（AOT兼容版本）
        /// </summary>
        /// <typeparam name="TResult">响应类型</typeparam>
        /// <param name="manager">HTTP请求管理器</param>
        /// <param name="method">HTTP方法</param>
        /// <param name="requestUri">请求URI</param>
        /// <param name="responseTypeInfo">响应的JSON类型信息</param>
        /// <param name="options">请求选项</param>
        /// <returns>反序列化后的响应对象</returns>
        public static async Task<TResult?> SendWithOptionsAsync<TResult>(
            this HttpRequestManager manager,
            HttpMethod method,
            string requestUri,
            JsonTypeInfo<TResult> responseTypeInfo,
            RequestOptions options)
        {
            ArgumentNullException.ThrowIfNull(manager);
            ArgumentNullException.ThrowIfNull(method);
            ArgumentException.ThrowIfNullOrEmpty(requestUri);
            ArgumentNullException.ThrowIfNull(responseTypeInfo);
            ArgumentNullException.ThrowIfNull(options);

            var builder = manager.CreateRequestWithOptions(method, requestUri, options);

            using var response = await builder.SendAsync(options.CancellationToken).ConfigureAwait(false);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync(options.CancellationToken).ConfigureAwait(false);
            return await JsonSerializer.DeserializeAsync(stream, responseTypeInfo, options.CancellationToken).ConfigureAwait(false);
        }

        /// <summary>
        /// 使用请求选项发送JSON请求并反序列化响应
        /// </summary>
        /// <typeparam name="TValue">请求体类型</typeparam>
        /// <typeparam name="TResult">响应类型</typeparam>
        /// <param name="manager">HTTP请求管理器</param>
        /// <param name="method">HTTP方法</param>
        /// <param name="requestUri">请求URI</param>
        /// <param name="value">要序列化为JSON的对象</param>
        /// <param name="options">请求选项</param>
        /// <returns>反序列化后的响应对象</returns>
        [RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        [RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        public static async Task<TResult?> SendJsonWithOptionsAsync<TValue, TResult>(
            this HttpRequestManager manager,
            HttpMethod method,
            string requestUri,
            TValue value,
            RequestOptions options)
        {
            ArgumentNullException.ThrowIfNull(manager);
            ArgumentNullException.ThrowIfNull(method);
            ArgumentException.ThrowIfNullOrEmpty(requestUri);
            ArgumentNullException.ThrowIfNull(options);

            var builder = manager.CreateJsonRequest(method, requestUri, options);
            builder.WithJsonContent(value);

            using var response = await builder.SendAsync(options.CancellationToken).ConfigureAwait(false);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync(options.CancellationToken).ConfigureAwait(false);
            return await JsonSerializer.DeserializeAsync<TResult>(stream, cancellationToken: options.CancellationToken).ConfigureAwait(false);
        }

        /// <summary>
        /// 使用请求选项发送JSON请求并反序列化响应（AOT兼容版本）
        /// </summary>
        /// <typeparam name="TValue">请求体类型</typeparam>
        /// <typeparam name="TResult">响应类型</typeparam>
        /// <param name="manager">HTTP请求管理器</param>
        /// <param name="method">HTTP方法</param>
        /// <param name="requestUri">请求URI</param>
        /// <param name="value">要序列化为JSON的对象</param>
        /// <param name="requestTypeInfo">请求体的JSON类型信息</param>
        /// <param name="responseTypeInfo">响应的JSON类型信息</param>
        /// <param name="options">请求选项</param>
        /// <returns>反序列化后的响应对象</returns>
        public static async Task<TResult?> SendJsonWithOptionsAsync<TValue, TResult>(
            this HttpRequestManager manager,
            HttpMethod method,
            string requestUri,
            TValue value,
            JsonTypeInfo<TValue> requestTypeInfo,
            JsonTypeInfo<TResult> responseTypeInfo,
            RequestOptions options)
        {
            ArgumentNullException.ThrowIfNull(manager);
            ArgumentNullException.ThrowIfNull(method);
            ArgumentException.ThrowIfNullOrEmpty(requestUri);
            ArgumentNullException.ThrowIfNull(requestTypeInfo);
            ArgumentNullException.ThrowIfNull(responseTypeInfo);
            ArgumentNullException.ThrowIfNull(options);

            var builder = manager.CreateJsonRequest(method, requestUri, options);
            builder.WithJsonContent(value, requestTypeInfo);

            using var response = await builder.SendAsync(options.CancellationToken).ConfigureAwait(false);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync(options.CancellationToken).ConfigureAwait(false);
            return await JsonSerializer.DeserializeAsync(stream, responseTypeInfo, options.CancellationToken).ConfigureAwait(false);
        }

        /// <summary>
        /// 使用请求选项进行流式下载到指定流并报告进度
        /// </summary>
        /// <param name="manager">HTTP请求管理器</param>
        /// <param name="method">HTTP方法</param>
        /// <param name="requestUri">请求URI</param>
        /// <param name="destination">目标流</param>
        /// <param name="options">请求选项</param>
        /// <param name="bufferSize">缓冲区大小，默认81920字节(80KB)</param>
        /// <returns>下载的总字节数</returns>
        public static async Task<long> DownloadWithOptionsAsync(
            this HttpRequestManager manager,
            HttpMethod method,
            string requestUri,
            Stream destination,
            RequestOptions options,
            int bufferSize = 81920)
        {
            ArgumentNullException.ThrowIfNull(manager);
            ArgumentNullException.ThrowIfNull(method);
            ArgumentException.ThrowIfNullOrEmpty(requestUri);
            ArgumentNullException.ThrowIfNull(destination);
            ArgumentNullException.ThrowIfNull(options);

            var builder = manager.CreateRequestWithOptions(method, requestUri, options);
            return await builder.DownloadToStreamAsync(
                destination,
                options.DownloadProgress,
                bufferSize,
                options.CancellationToken).ConfigureAwait(false);
        }
    }
}
